package tr.edu.metu.is.mega.client.core.event;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import tr.edu.metu.is.mega.common.dto.BaseDTO;

/**
 * Singleton event bus for multi-screenpart selection events.
 */
public final class SelectionEventBus {

    private static SelectionEventBus instance = null;

    private Map<Class<?>, List<SelectionEventListener<? extends BaseDTO>>> map = null;

    /**
     * Hidden constructor.
     */
    private SelectionEventBus() {
        map = new HashMap<Class<?>, List<SelectionEventListener<? extends BaseDTO>>>();
    }

    /**
     * Returns singleton instance of this.
     * 
     * @return singleton instance of this
     */
    public static SelectionEventBus getInstance() {
        if (instance == null) {
            instance = new SelectionEventBus();
        }
        return instance;
    }

    /**
     * Registers a selection event listener for events fired from specified
     * type.
     * 
     * @param clazz type of event producer
     * @param listener event listener
     */
    public void registerListener(Class<?> clazz, SelectionEventListener<? extends BaseDTO> listener) {
        List<SelectionEventListener<? extends BaseDTO>> list = map.get(clazz);
        if (list == null) {
            list = new ArrayList<SelectionEventListener<? extends BaseDTO>>();
            map.put(clazz, list);
        }
        if (!list.contains(listener)) {
            list.add(listener);
        }
    }

    /**
     * Unregisters a selection event listener.
     * 
     * @param clazz type of event producer
     * @param listener event listener
     */
    public void unregisterListener(Class<?> clazz, SelectionEventListener<? extends BaseDTO> listener) {
        List<SelectionEventListener<? extends BaseDTO>> list = map.get(clazz);
        if (list != null) {
            list.remove(listener);
        }
    }

    /**
     * Fires event.
     * 
     * @param source source instance
     * @param selectedObject selected object
     * @param <T> type modifier
     */
    @SuppressWarnings("unchecked")
    public <T extends BaseDTO> void fireEvent(Object source, T selectedObject) {
        List<SelectionEventListener<? extends BaseDTO>> listeners = map.get(source.getClass());
        for (SelectionEventListener<? extends BaseDTO> listener : listeners) {
            ((SelectionEventListener<T>) listener).selectionChanged(selectedObject);
        }
    }

}
